package hu.uszeged.inf.wlab.stunner.screens.discovery;

import hu.uszeged.inf.wlab.stunner.R;
import hu.uszeged.inf.wlab.stunner.database.STUNnerContract;
import hu.uszeged.inf.wlab.stunner.database.dtos.BatteryInfoDTO;
import hu.uszeged.inf.wlab.stunner.database.dtos.DiscoveryDTO;
import hu.uszeged.inf.wlab.stunner.database.dtos.MobileNetInfoDTO;
import hu.uszeged.inf.wlab.stunner.database.dtos.WifiInfoDTO;
import hu.uszeged.inf.wlab.stunner.screens.bookmarks.BookmarksActivity;
import hu.uszeged.inf.wlab.stunner.screens.discovery.infobuilders.DiscoveryInfoBuilder;
import hu.uszeged.inf.wlab.stunner.screens.discovery.task.DeviceConnectionTester;
import hu.uszeged.inf.wlab.stunner.screens.discovery.task.StunDiscoveryTask;
import hu.uszeged.inf.wlab.stunner.utils.Constants;
import hu.uszeged.inf.wlab.stunner.utils.DiscoveryResult;

import java.util.Random;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.annotation.TargetApi;
import android.app.AlertDialog.Builder;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.graphics.drawable.AnimationDrawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.ActionBarActivity;
import android.text.Html;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.maps.model.LatLng;

import de.javawi.jstun.test.DiscoveryInfo;

/**
 * The launcher {@link ActionBarActivity}. Displays the available location and connection data. Also stores the results in the local
 * database.
 * 
 * @author szelezsant
 */
public class MainActivity extends ActionBarActivity implements StunDiscoveryTask.PostExecute, DeviceConnectionTester.TestEventsListener {

	/** String to declare the entry of the shared preferences when the user decides to accepts the terms. */
	private static final String DISCLAIMER_ACCEPTED = "accepted";
	/** The criteria used when acquiring location on location changed events. */
	private static final int DISTANCE_CRITERIA = 100;

	/** The latest acquired location. */
	private static LatLng location;

	/** Random. */
	private final Random random = new Random();
	/** Flag to indicate the first run of the test. */
	private boolean first = true;
	/** Flag to indicate if error has ocurred. */
	private boolean error = true;

	/** Discovery dto to represent the discovered data. */
	private DiscoveryDTO discoveryDTO;
	/** Stores the battery information. */
	private BatteryInfoDTO batteryDTO;
	/** Stores the WIFI information. */
	private WifiInfoDTO wifiInfoDTO;
	/** Stores the cellular information. */
	private MobileNetInfoDTO mobileNetDTO;

	/** Textview that indicates whether we are behind NAT. */
	private TextView natHeader;

	/** Textview that indicates nat type. */
	private TextView natType;
	/** Textview that indicates public IP. */
	private TextView natIP;

	/** Textview that indicates connection type WIFI or mobile. */
	private TextView phoneConnectionType;

	/** Textview that indicates phones IP. */
	private TextView phoneIP;
	/** Textview that indicates carrier if SIM is present. */
	private TextView phoneCarrier;
	/** Textview that indicates mobile data connection type. */
	private TextView phoneDataConnectionType;
	/** Textview that indicates MAC address. */
	private TextView phoneMAC;
	/** Textview that indicates connected WIFI SSID if connected. */
	private TextView phoneSSID;
	/** Textview that indicates WIFI link speed if connected. */
	private TextView phoneLinkSpeed;
	/** Textview that indicates WIFI signal strength if connected. */
	private TextView phoneSingalStrength;

	/** The bookmark menu item. */
	private MenuItem bookmarkMenuItem;

	/** Connector item to cloud. */
	private View connector;
	/** Connection mode indicator. */
	private ImageView connectionMode;

	/** Textview that indicates information about stun server address. */
	private TextView internetInfo;

	/** Textview for lo progress indication. */
	private TextView log;

	/** Holder for actual server address. */
	private String serverAddress;
	/** Holder for actual server port. */
	private int serverPort;

	/** {@link LocationListener} implementation. */
	private final LocationListener locationListener = new LocationListener() {
		@Override
		public void onLocationChanged(final Location changedLocation) {
			// update it
			MainActivity.location = new LatLng(changedLocation.getLatitude(), changedLocation.getLongitude());
			Log.v(MainActivity.class.getSimpleName(), "Location update arrived!");
		}

		@Override
		public void onStatusChanged(final String provider, final int status, final Bundle extras) {
			// nothing to do
		}

		@Override
		public void onProviderEnabled(final String provider) {
			// nothing to do
		}

		@Override
		public void onProviderDisabled(final String provider) {
			// nothing to do
		}
	};

	/**
	 * BroadcastReceiver to receive battery status information.
	 */
	private final BroadcastReceiver batteryReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(final Context context, final Intent intent) {
			if (null == batteryDTO || 0 == batteryDTO.getId()) {
				batteryDTO = new BatteryInfoDTO();
				int chargingSate = BatteryManager.BATTERY_STATUS_UNKNOWN;
				final Bundle extras = intent.getExtras();
				if (extras.getInt(BatteryManager.EXTRA_STATUS, -1) == BatteryManager.BATTERY_STATUS_CHARGING) {
					if (extras.containsKey(BatteryManager.EXTRA_PLUGGED)) {
						chargingSate = extras.getInt(BatteryManager.EXTRA_PLUGGED);
					} else {
						chargingSate = extras.getInt(BatteryManager.EXTRA_STATUS);
					}
				}
				batteryDTO.setChargingState(chargingSate);
				batteryDTO.setPercentage(extras.getInt(BatteryManager.EXTRA_LEVEL, -1)
						/ extras.getInt(BatteryManager.EXTRA_SCALE, -1));
				batteryDTO.setHealth(extras.getInt(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN));
				if (extras.containsKey(BatteryManager.EXTRA_TEMPERATURE)) {
					batteryDTO.setTemperature(extras.getInt(BatteryManager.EXTRA_TEMPERATURE, -1));
				}
				if (extras.containsKey(BatteryManager.EXTRA_VOLTAGE)) {
					batteryDTO.setVoltage(extras.getInt(BatteryManager.EXTRA_VOLTAGE));
				}
			}
		}
	};

	/*
	 * activity lifecycle mgmt
	 */
	@Override
	protected void onCreate(final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		// location updates
		if (location == null) {
			location = new LatLng(0.0, 0.0);
		}
		final LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
		// If any of the providers are enabled
		if (locationManager.getProviders(true).size() > 0) {
			// Register the listener with the Location Manager to receive location updates
			locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, DISTANCE_CRITERIA, locationListener);
		}

		((ImageView) findViewById(R.id.phone)).setOnClickListener(new DeviceConnectionTester(this, this));

		// TODO [szelezsant] should do this only once
		final AccountManager accountManager = (AccountManager) getSystemService(ACCOUNT_SERVICE);
		if (accountManager.addAccountExplicitly(new Account(Constants.DUMMY_ACCOUNT, Constants.ACCOUNT_TYPE), null, null)) {
			Log.i(getClass().getSimpleName(), "dummy account registered successfully");
		}

		natHeader = (TextView) findViewById(R.id.natHeader);
		natType = (TextView) findViewById(R.id.natType);
		natIP = (TextView) findViewById(R.id.natIP);

		phoneConnectionType = (TextView) findViewById(R.id.phoneConnectionType);

		phoneIP = (TextView) findViewById(R.id.phoneIP);

		phoneCarrier = (TextView) findViewById(R.id.phoneCarrier);
		phoneDataConnectionType = (TextView) findViewById(R.id.phoneDataConnectionType);

		phoneMAC = (TextView) findViewById(R.id.phoneMAC);
		phoneSSID = (TextView) findViewById(R.id.phoneSSID);
		phoneLinkSpeed = (TextView) findViewById(R.id.phoneLinkSpeed);
		phoneSingalStrength = (TextView) findViewById(R.id.phoneSingalStrength);

		connector = findViewById(R.id.connector);
		connectionMode = (ImageView) findViewById(R.id.connectionMode);

		internetInfo = (TextView) findViewById(R.id.internetInfo);

		log = (TextView) findViewById(R.id.log);

		final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
		if (!preferences.contains(DISCLAIMER_ACCEPTED)) {
			firstRunDisclaimer();
		}
	}

	@Override
	protected void onResume() {
		super.onResume();
		final IntentFilter filter = new IntentFilter();
		filter.addAction(Intent.ACTION_POWER_CONNECTED);
		filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
		filter.addAction(Intent.ACTION_BATTERY_CHANGED);
		registerReceiver(batteryReceiver, filter);
	}

	@Override
	protected void onPause() {
		unregisterReceiver(batteryReceiver);
		super.onPause();
	}

	@Override
	protected void onDestroy() {
		final LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
		locationManager.removeUpdates(locationListener);
		super.onDestroy();
	}

	/*
	 * menu handling
	 */
	@Override
	public boolean onCreateOptionsMenu(final Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		bookmarkMenuItem = menu.findItem(R.id.action_bookmark);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(final MenuItem item) {
		if (R.id.action_show_bookmarks == item.getItemId()) {

			/* persist the actual discovery */
			if (null != discoveryDTO) {
				getContentResolver().insert(STUNnerContract.Discovery.CONTENT_URI,
						STUNnerContract.Discovery.createContentValues(discoveryDTO));
			}

			startActivity(new Intent(this, BookmarksActivity.class));
			return true;
		} else if (R.id.action_bookmark == item.getItemId()) {
			if (null != discoveryDTO) {
				discoveryDTO.setBookmarked(!discoveryDTO.isBookmarked());

				final Cursor cursor = getContentResolver().query(
						ContentUris.withAppendedId(STUNnerContract.Discovery.CONTENT_URI, discoveryDTO.getIdentifier()), null, null, null,
						null);
				/* if the sync adapter has deleted the discovery already, set pending to false, to prevent multiple uploads of the same data */
				if (null == cursor || cursor.getCount() == 0) {
					discoveryDTO.setPending(false);
				}
			}
			Toast.makeText(MainActivity.this, discoveryDTO.isBookmarked() ? R.string.bookmark_added : R.string.bookmark_removed,
					Toast.LENGTH_LONG).show();
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	/*
	 * DeviceConnectionTester.TestEventsListener callbacks
	 */
	@Override
	public void onTestStart() {
		((ImageView) findViewById(R.id.phone)).setEnabled(false);
		if (first || error) {
			first = false;
			error = false;
		} else {
			bookmarkMenuItem.setVisible(false);
			slideToShowText(false, discoveryDTO.getDiscoveryResult());
			initNatType();
		}
		final int randomNum = random.nextInt(getResources().getStringArray(R.array.servers).length - 0) + 0;
		serverAddress = getResources().getStringArray(R.array.servers)[randomNum];
		serverPort = getResources().getIntArray(R.array.ports)[randomNum];
		setServerAddress(serverAddress);
		showLog(true);
		showWifiLoading(true);

		/* hide the marker and set to default state. */
		bookmarkMenuItem.setVisible(false);
	}

	// Device connectivity callbacks
	@Override
	public void onConnectionError(final boolean userDeclined) {
		Toast.makeText(this, R.string.test_failed_please_try_again, Toast.LENGTH_SHORT).show();
		showWifiLoading(false);
		((ImageView) findViewById(R.id.phone)).setEnabled(true);
		showLog(false);
		error = true;
	}

	@Override
	public void onConnectionNotReady() {
		Toast.makeText(this, R.string.test_failed_please_try_again, Toast.LENGTH_SHORT).show();
		showWifiLoading(false);
		((ImageView) findViewById(R.id.phone)).setEnabled(true);
		showLog(false);
		error = true;
	}

	@Override
	public void onTestComplete(final String localIP, final MobileNetInfoDTO mobileNetInfoDTO, final WifiInfoDTO wifiDTO) {
		this.mobileNetDTO = mobileNetInfoDTO;
		this.wifiInfoDTO = wifiDTO;
		showRemoteLoading(true);

		if (localIP == null) {
			phoneIP.setText(R.string.n_a);
		} else {
			phoneIP.setText(localIP);
		}

		if (wifiDTO.getSsid() == null) {
			phoneConnectionType.setText(R.string.mobile_data_connected);
			phoneSSID.setText(R.string.n_a);
			phoneLinkSpeed.setText(R.string.n_a);
			phoneSingalStrength.setText(R.string.n_a);
		} else {
			phoneConnectionType.setText(R.string.wifi_connected);
			phoneSSID.setText(wifiDTO.getSsid() == null ? getString(R.string.n_a) : wifiDTO.getSsid());
			phoneLinkSpeed.setText(wifiDTO.getBandwidth() == null ? getString(R.string.n_a) : wifiDTO.getBandwidth());
			phoneSingalStrength.setText(wifiDTO.getRssi() == 0 ? getString(R.string.n_a) : wifiDTO.getRssi()
					+ getString(R.string.decibel));
		}

		// mandatory data always shown
		phoneCarrier.setText(mobileNetInfoDTO.getCarrier() == null ? getString(R.string.n_a) : mobileNetInfoDTO.getCarrier());
		phoneDataConnectionType.setText(mobileNetInfoDTO.getCarrier() == null ? getString(R.string.n_a) : mobileNetInfoDTO
				.getNetworkType());
		phoneMAC.setText(wifiDTO.getMacAddress() == null ? getString(R.string.n_a) : wifiDTO.getMacAddress());

		// starting new discovery, so create a new discovery DTO.
		discoveryDTO = new DiscoveryDTO();
		discoveryDTO.setLocalIP(localIP);
		new StunDiscoveryTask(this).execute(StunDiscoveryTask.createTestArguments(
				serverAddress, serverPort, localIP));
	}

	// StunDiscoveryTask callback
	@Override
	public void doPostExecute(final DiscoveryInfo info) {

		// test failed
		if (info == null) {
			Toast.makeText(this, R.string.test_failed_please_try_again, Toast.LENGTH_SHORT).show();
			startInprogressAnimation(false);
			showLog(false);
			error = true;
			return;
		}

		final DiscoveryInfoBuilder infoBuilder = new DiscoveryInfoBuilder(info, this);
		if (null != info.getPublicIP()) {
			discoveryDTO.setPublicIP(info.getPublicIP().getHostAddress());
		}
		// just invoked to set nat type
		infoBuilder.getInfo();
		discoveryDTO.setDiscoveryResultCode(infoBuilder.getDiscoveryResultCode());

		if (discoveryDTO.getDiscoveryResult().equals(DiscoveryResult.OPEN_ACCESS)) {
			natHeader.setText(R.string.open_access);
			natType.setText(R.string.n_a);
			natIP.setText(phoneIP.getText());
		} else {
			natHeader.setText(R.string.nat_detected);
			natIP.setText(info.getPublicIP() == null ? getString(R.string.n_a) : info.getPublicIP().getHostAddress());
			natType.setText(getString(discoveryDTO.getDiscoveryResult().getResourceId()));
		}
		setNatType(discoveryDTO.getDiscoveryResult());

		startInprogressAnimation(false);
		showLog(false);
		slideToShowText(true, discoveryDTO.getDiscoveryResult());
		tryPersistDiscovery();
		bookmarkMenuItem.setVisible(true);
	}

	/**
	 * Sets the STUN server's address.
	 * 
	 * @param text - the server address.
	 */
	private void setServerAddress(final String text) {
		final Animation serverFadeIn = AnimationUtils.loadAnimation(this, R.anim.fade_in);
		internetInfo.setText(text);
		internetInfo.startAnimation(serverFadeIn);
	}

	/**
	 * @param show whether fade in or out log.
	 */
	private void showLog(final boolean show) {
		final Animation logFadeInOut = AnimationUtils.loadAnimation(this, show ? R.anim.fade_in : R.anim.fade_out);
		if (show) {
			log.setText("");
		} else {
			logFadeInOut.setAnimationListener(new AnimationListener() {
				@Override
				public void onAnimationStart(final Animation animation) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onAnimationRepeat(final Animation animation) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onAnimationEnd(final Animation animation) {
					log.setText("");
				}
			});
		}
		logFadeInOut.setFillAfter(true);
		logFadeInOut.setFillEnabled(true);
		log.startAnimation(logFadeInOut);
	}

	/**
	 * @param currentLog current log row by jstun.
	 */
	public void updateLog(final String currentLog) {
		if (log.getText().length() > 0) {
			log.setText(log.getText() + "\n" + getString(R.string.stun_console) + currentLog);
		} else {
			log.setText(getString(R.string.stun_console) + currentLog);
		}
	}

	/**
	 * @param start based on this wifi signal and cloud animation and phone clickability is set.
	 */
	private void startInprogressAnimation(final boolean start) {
		showWifiLoading(start);
		showRemoteLoading(start);
		((ImageView) findViewById(R.id.phone)).setEnabled(!start);
	}

	/**
	 * @param isLoading - the flag to determine if the loading is in progress.
	 */
	@SuppressWarnings("deprecation")
	@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
	private void showWifiLoading(final boolean isLoading) {
		final ImageView wifi = (ImageView) findViewById(R.id.wifisignal);

		final AnimationDrawable wifiFrameAnimation = (AnimationDrawable) wifi.getBackground();
		if (isLoading) {
			wifiFrameAnimation.start();
		} else {
			// reset animation to first
			if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
				wifi.setBackgroundDrawable(null);
			} else {
				wifi.setBackground(null);
			}
			wifi.setBackgroundResource(R.drawable.wifisignal);
			wifiFrameAnimation.stop();
		}
	}

	/**
	 * @param isLoading - the flag to determine if the loading is in progress.
	 */
	@SuppressWarnings("deprecation")
	@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
	private void showRemoteLoading(final boolean isLoading) {
		final ImageView cloud = (ImageView) findViewById(R.id.cloud);
		cloud.setBackgroundResource(R.drawable.cloud);

		final AnimationDrawable cloudFrameAnimation = (AnimationDrawable) cloud.getBackground();
		if (isLoading) {
			cloudFrameAnimation.start();
		} else {
			// reset animation to first
			if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
				cloud.setBackgroundDrawable(null);
			} else {
				cloud.setBackground(null);
			}
			cloud.setBackgroundResource(R.drawable.cloud_standby);
			cloudFrameAnimation.stop();
		}
	}

	/**
	 * Slides down and up elements to show result text.
	 * 
	 * @param show - flag to toggle animations.
	 * @param result - the {@link DiscoveryResult} object to gain information from.
	 */
	private void slideToShowText(final boolean show, final DiscoveryResult result) {
		final View phone = findViewById(R.id.phoneContainer);
		final View remote = findViewById(R.id.remoteContainer);
		final View glory = findViewById(R.id.glory);
		final View labels = findViewById(R.id.labelsContainer);

		final Animation animationDown = AnimationUtils.loadAnimation(this, show ? R.anim.slide_out_down : R.anim.slide_in_down);
		animationDown.setFillAfter(true);
		animationDown.setFillEnabled(true);

		final Animation animationUp = AnimationUtils.loadAnimation(this, show ? R.anim.slide_out_up : R.anim.slide_in_up);
		animationUp.setFillAfter(true);
		animationUp.setFillEnabled(true);

		final Animation animationUpGlory = AnimationUtils.loadAnimation(this, show ? R.anim.slide_out_up : R.anim.slide_in_up);
		animationUpGlory.setFillAfter(true);
		animationUpGlory.setFillEnabled(true);

		final Animation animationFadein = AnimationUtils.loadAnimation(this, show ? R.anim.fade_in : R.anim.fade_out);
		animationFadein.setFillAfter(true);
		animationFadein.setFillEnabled(true);

		if (show) {
			labels.startAnimation(animationFadein);
			phone.startAnimation(animationDown);
			if (!DiscoveryResult.OPEN_ACCESS.equals(result)) {
				glory.startAnimation(animationUpGlory);
				remote.startAnimation(animationUp);
			}
		} else {
			phone.startAnimation(animationDown);
			if (!DiscoveryResult.OPEN_ACCESS.equals(result)) {
				glory.startAnimation(animationUpGlory);
				remote.startAnimation(animationUp);
			}
			labels.startAnimation(animationFadein);
		}

	}

	/**
	 * Initializes back NAT bubble visibility and connector visibility is invisible.
	 */
	private void initNatType() {
		if (discoveryDTO != null && DiscoveryResult.OPEN_ACCESS.equals(discoveryDTO.getDiscoveryResult())) {
			final Animation animationFadein = AnimationUtils.loadAnimation(this, R.anim.fade_in);
			connector.startAnimation(animationFadein);
		}
		final Animation animationFadein = AnimationUtils.loadAnimation(this, R.anim.fade_in);
		connectionMode.setImageResource(R.drawable.nat_unknown);
		connectionMode.startAnimation(animationFadein);
	}

	/**
	 * @param result this result is the basis what should be set in the bubble.
	 */
	private void setNatType(final DiscoveryResult result) {
		final Animation animationFadein = AnimationUtils.loadAnimation(this, R.anim.fade_in);
		switch (result) {
			case OPEN_ACCESS:
				final Animation animationFadeout1 = AnimationUtils.loadAnimation(this, R.anim.fade_out);
				final Animation animationFadeout2 = AnimationUtils.loadAnimation(this, R.anim.fade_out);
				animationFadeout1.setFillAfter(true);
				animationFadeout1.setFillEnabled(true);
				animationFadeout2.setFillAfter(true);
				animationFadeout2.setFillEnabled(true);
				connector.startAnimation(animationFadeout1);
				connectionMode.startAnimation(animationFadeout2);
				break;
			case FULL_CONE:
				connectionMode.setImageResource(R.drawable.nat_full_cone);
				connectionMode.startAnimation(animationFadein);
				break;
			case RESTRICTED_CONE:
				connectionMode.setImageResource(R.drawable.nat_address_restricted);
				connectionMode.startAnimation(animationFadein);
				break;
			case PORT_RESTRICTED_CONE:
				connectionMode.setImageResource(R.drawable.nat_address_port_restricted);
				connectionMode.startAnimation(animationFadein);
				break;
			case SYMMETRIC_CONE:
				connectionMode.setImageResource(R.drawable.nat_symmetric);
				connectionMode.startAnimation(animationFadein);
				break;
			case ERROR:
			case UNKNOWN:
			case SYMMETRIC_FIREWALL:
			case FIREWALL_BLOCKS:
			default:
				connectionMode.setImageResource(R.drawable.nat_unknown);
				connectionMode.startAnimation(animationFadein);
				break;
		}
	}

	/**
	 * Disclaimer shown on first run.
	 */
	private void firstRunDisclaimer() {
		final Builder builder = new Builder(this);
		builder.setTitle(R.string.disclaimer);
		builder.setMessage(Html.fromHtml(Constants.LICENSE));
		builder.setPositiveButton(R.string.accept, new OnClickListener() {
			@Override
			public void onClick(final DialogInterface arg0, final int arg1) {
				final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
				final Editor editor = preferences.edit();
				editor.putBoolean(DISCLAIMER_ACCEPTED, true);
				editor.commit();
				arg0.dismiss();
			}
		});
		builder.setNegativeButton(R.string.deny, new OnClickListener() {
			@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
			@Override
			public void onClick(final DialogInterface arg0, final int arg1) {
				MainActivity.this.finish();
				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
					final Uri packageUri = Uri.parse("package:" + getPackageName());
					final Intent uninstallIntent =
							new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
					startActivity(uninstallIntent);
				}
			}
		});
		builder.show();
	}

	/**
	 * Tries to persist the discovery data (if all mandatory data is present). In case of successful insert, the menu item 'Bookmark' will
	 * be visible.
	 */
	private void tryPersistDiscovery() {

		if (null != batteryDTO) {
			final Uri insertedBattery = getContentResolver().insert(STUNnerContract.BatteryInfo.CONTENT_URI,
					STUNnerContract.BatteryInfo.createContentValues(batteryDTO));
			discoveryDTO.setBatteryInfoId(Long.valueOf(insertedBattery.getLastPathSegment()));
		}
		if (null != wifiInfoDTO) {
			final Uri insertedWifi = getContentResolver().insert(STUNnerContract.WifiInfo.CONTENT_URI,
					STUNnerContract.WifiInfo.createContentValues(wifiInfoDTO));
			discoveryDTO.setBatteryInfoId(Long.valueOf(insertedWifi.getLastPathSegment()));
		}
		if (null != mobileNetDTO) {
			final Uri insertedMobile = getContentResolver().insert(STUNnerContract.MobileNetInfo.CONTENT_URI,
					STUNnerContract.MobileNetInfo.createContentValues(mobileNetDTO));
			discoveryDTO.setBatteryInfoId(Long.valueOf(insertedMobile.getLastPathSegment()));
		}

		discoveryDTO.setLatitude(location.latitude);
		discoveryDTO.setLongitude(location.longitude);

		/* persist discovery */
		final Uri insertedDisco = getContentResolver().insert(STUNnerContract.Discovery.CONTENT_URI,
				STUNnerContract.Discovery.createContentValues(discoveryDTO));
		discoveryDTO.setIdentifier(Long.valueOf(insertedDisco.getLastPathSegment()));

		final Bundle settingsBundle = new Bundle();
		settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
		settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);

		final AccountManager manager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
		final Account[] accounts = manager.getAccountsByType(getString(R.string.account_type));
		if (null != accounts && accounts.length == 1) {
			ContentResolver.requestSync(accounts[0], STUNnerContract.AUTHORITY, settingsBundle);
		}
	}
}
